package fr.blogger.web.bean.securite;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.faces.FacesException;
import javax.faces.application.NavigationHandler;
import javax.faces.application.ViewExpiredException;
import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerWrapper;
import javax.faces.context.FacesContext;
import javax.faces.event.ExceptionQueuedEvent;
import javax.faces.event.ExceptionQueuedEventContext;

import org.springframework.security.web.authentication.rememberme.CookieTheftException;

import com.sun.faces.context.FacesFileNotFoundException;

import fr.blogger.web.outils.UtilsJsf;

public class CustomExceptionHandler extends ExceptionHandlerWrapper {

	public final static String PACKAGE_APPLICATION = "fr.blogger";

	private ExceptionHandler wrapped;

	public CustomExceptionHandler(ExceptionHandler exception) {
		this.wrapped = exception;
	}

	@Override
	public ExceptionHandler getWrapped() {
		return wrapped;
	}

	@Override
	public void handle() throws FacesException {

		final Iterator<ExceptionQueuedEvent> iterator = getUnhandledExceptionQueuedEvents().iterator();
		while (iterator.hasNext()) {
			ExceptionQueuedEvent event = iterator.next();
			ExceptionQueuedEventContext context = (ExceptionQueuedEventContext) event.getSource();
			Throwable exception = context.getException();
			final FacesContext facesContext = FacesContext.getCurrentInstance();
			final NavigationHandler navigation = facesContext.getApplication().getNavigationHandler();
			try {
				String result = doNavigation(exception, facesContext);
				navigation.handleNavigation(facesContext, null, result);
				facesContext.renderResponse();
			} finally {
				iterator.remove();
			}
		}
		getWrapped().handle();
	}

	private String doNavigation(Throwable exception, FacesContext facesContext) {
		if (exception instanceof ViewExpiredException || exception instanceof CookieTheftException) {
			return "/accueil.xhtml";
		}
		if (exception instanceof FacesFileNotFoundException) {
			return "/pages/public/errors/404.xhtml";
		}
		// LOGGER
		initTechnicalError(exception, facesContext);
		UtilsJsf.ajoutMessageError("Une erreur technique est survenue. Si le problème persiste, merci de contacter le support technique.");
		return "/pages/public/errors/500.xhtml";
	}

	private void initTechnicalError(Throwable exception, FacesContext facesContext) {
		while (exception.getCause() != null) {
			exception = exception.getCause();
		}
		final Map<String, Object> requestMap = facesContext.getExternalContext().getRequestMap();
		requestMap.put("exception.class", exception.getClass());
		requestMap.put("exception.message", exception.getMessage());
		List<String> listeTrace = new ArrayList();
		for (StackTraceElement trace : exception.getStackTrace()) {
			if (trace.getClassName().startsWith(PACKAGE_APPLICATION)) {
				listeTrace.add(trace.toString());
			}
		}
		requestMap.put("exception.stacktrace", listeTrace);
	}

}
